import AlipaySdk, { AlipaySdkCommonResult } from 'alipay-sdk';
import * as fs from 'fs';
import { ServiceException } from '../common/excpetion';

export class AlipayService {
    private appId = "2019060465491314";
    // 沙箱
    // private appId = "2016102000727853";
    private alipaySdk: AlipaySdk;
    constructor() {
        let privateKey = fs.readFileSync(process.cwd() + '/certificate/alipay_private_2048.pem', 'ascii');
        this.alipaySdk = new AlipaySdk({
            appId: this.appId,
            privateKey,
            gateway: "https://openapi.alipay.com/gateway.do",
            // gateway: "https://openapi.alipaydev.com/gateway.do",  // 沙箱网关
            alipayPublicKey: fs.readFileSync(process.cwd() + '/certificate/alipay_pub_2048.pem', 'ascii'),
        });
    }

    private GetAlipayObj(type: 'out' | 'inner' = 'out') {
        let appId: string;
        if (type == 'out') {
            // 第三方支付，用户服务商角色门店代收款
            appId = '2019060465491314';
        }
        else {
            // 用于coeus 系统充值，购买模块交易
            // appId = '2021001118696791';
            appId = '2018122062578620';
        }

        let privateKey = fs.readFileSync(process.cwd() + '/certificate/alipay_private_2048.pem', 'ascii');
        return new AlipaySdk({
            appId,
            privateKey,
            gateway: "https://openapi.alipay.com/gateway.do",
            // gateway: "https://openapi.alipaydev.com/gateway.do",  // 沙箱网关
            alipayPublicKey: fs.readFileSync(process.cwd() + '/certificate/alipay_pub_2048.pem', 'ascii'),
        });
    }

    async TradePay(authCode: string, orderPaymentId: string, payAmount: number, subject: string, appAuthToken?: string) {
        try {
            let params: any = {
                // appAuthToken: "201906BB329311a478b44b0b996bfce28eccdX08",
                bizContent: {
                    outTradeNo: orderPaymentId,                   //支付记录id
                    subject,                                      //订单标题
                    scene: 'bar_code',
                    totalAmount: payAmount,                       //收款金额
                    authCode,                                     //收款码
                    extendParams: {
                        sysServiceProviderId: this.appId
                    }
                }
            };
            if (appAuthToken) {
                params.appAuthToken = appAuthToken;
            }

            let result = await this.alipaySdk.exec('alipay.trade.pay', params);
            let cmdResult = result as AlipaySdkCommonResult;
            if (cmdResult.code == "10003" || cmdResult.code == "20000") {
                //等待支付 || 网络超时
                let payResult = await this.GetPayResult(orderPaymentId);
                return payResult;
            }
            else if (cmdResult.code == "10000") {
                //支付成功
                return cmdResult;
            }
            else {
                throw new ServiceException((<any>result).subMsg);
            }
        } catch (error) {
            throw new ServiceException(error);
        }
    }

    async TradeQuery(outTradeNo: string, type?) {
        try {
            let sdk = this.GetAlipayObj(type);
            let r = await sdk.exec('alipay.trade.query', {
                bizContent: {
                    outTradeNo
                }
            });
            return r;
        } catch (error) {
            return {
                code: '20000'
            };
        }
    }

    async TradeRefund(orderPaymentId: string, refundAmount: number, appAuthToken?: string) {
        try {
            let params: any = {
                bizContent: {
                    outTradeNo: orderPaymentId,
                    refundAmount
                }
            }
            if (appAuthToken) {
                params.appAuthToken = appAuthToken;
            }
            let r = await this.alipaySdk.exec('alipay.trade.refund', params);
            return r;
        } catch (error) {
            console.log('TradeRefundError', error);
            throw new ServiceException(error);
        }
    }

    async TradeCancel(outTradeNo: string) {
        try {
            let r = await this.alipaySdk.exec('alipay.trade.cancel', {
                bizContent: {
                    outTradeNo
                }
            });
            return r;
        } catch (error) {
            console.log('TradeCancelError', error);
        }
    }

    async AuthTokenApp(authCode: string) {
        try {
            let r = await this.alipaySdk.exec('alipay.open.auth.token.app', {
                bizContent: {
                    grantType: "authorization_code",
                    code: authCode
                }
            });
            console.log(r);
            return r;
        } catch (error) {
            console.log('AuthTokenAppError', error);
            throw new ServiceException(error);
        }
    }

    async AuthTokenAppQuery(authToken: string) {
        try {
            let r = await this.alipaySdk.exec('alipay.open.auth.token.app.query', {
                bizContent: {
                    appAuthToken: authToken
                }
            });

            return r;
        }
        catch (error) {
            console.log('AuthTokenAppQueryError', error);
            throw new ServiceException(error);
        }
    }

    async GetPayResult(orderPaymentId: string) {
        return new Promise((resolve, reject) => {
            let timer = setInterval(async () => {
                let r: any = await this.TradeQuery(orderPaymentId);
                if (r.code == "20000") {
                    //超时，发起交易取消
                    clearInterval(timer);
                    let rr = await this.TradeCancel(orderPaymentId);
                    reject(rr);
                }
                else {
                    if (r.tradeStatus == "WAIT_BUYER_PAY") {
                        //等待支付
                    }
                    else if (r.tradeStatus == "TRADE_CLOSED") {
                        clearInterval(timer);
                        resolve(r);
                    }
                    else if (r.tradeStatus == "TRADE_SUCCESS") {
                        clearInterval(timer);
                        resolve(r);
                    }
                    else if (r.tradeStatus == "TRADE_FINISHED") {
                        clearInterval(timer);
                        resolve(r);
                    }
                }

            }, 1000);
        });
    }

    async Precreate(outTradeNo: string, totalAmount: number, subject: string, body: string) {
        try {
            let aliSdk = this.GetAlipayObj("inner");
            let params = {
                bizContent: {
                    outTradeNo,
                    totalAmount,
                    subject,
                    body
                }
            }

            let result = await aliSdk.exec('alipay.trade.precreate', params) as AlipaySdkCommonResult;
            console.log(result);
            if (result.code == "10000") {
                return result;
            }
            else {
                throw new ServiceException((<any>result).subMsg);
            }
        } catch (error) {
            throw new ServiceException(error);
        }
    }
}